

#include <windows.h>
#include <bsp.h>

#include "ModuleExport.h"

volatile DWORD* g_pdwIntrRegs;
// bIntrType:0<inq>, 1<firq> 
void InterruptHandler(BYTE bIntrType);

void ChipInit_Intr()
{
	g_pdwIntrRegs = (UINT32*)OALPAtoVA(AK_BASE_REG_PA_CTRL, FALSE);

    // Mask and clear external interrupts
    REG32((UINT8*)g_pdwIntrRegs + IRQINT_MASK_REG_OFFSET) = 0;
    REG32((UINT8*)g_pdwIntrRegs + FIQINT_MASK_REG_OFFSET) = 0;
    REG32((UINT8*)g_pdwIntrRegs + INT_STA_ENA_OFFSET) &= 0xFFFF0000;
    //REG32((UINT8*)g_pIntrRegs + INT_STATUS_REG_OFFSET) = 0;   //need clear int sta?

    REG32((UINT8 *)g_pdwIntrRegs + IRQINT_MASK_REG_OFFSET)|= INT_STA_SYS_CTL;
    REG32((UINT8 *)g_pdwIntrRegs + FIQINT_MASK_REG_OFFSET)|= INT_STA_SYS_CTL;
}


void UndefHandler()
{
	EdbgOutputDebugString("\r\nUndefHandler halt!!!\r\n");
	while(1){}
}

typedef void* (*pfnSWIHldPv0)();
typedef void* (*pfnSWIHldPv1)(DWORD v0);
typedef void* (*pfnSWIHldPv2)(DWORD v0, DWORD v1);
typedef void* (*pfnSWIHldPv3)(DWORD v0, DWORD v1, DWORD v2);
typedef void* (*pfnSWIHldPv4)(DWORD v0, DWORD v1, DWORD v2, DWORD v3);
#define SWI_HDL_NUMB	100
void* s_pvSWIPfnS[SWI_HDL_NUMB]={NULL};
DWORD s_dwSWIVarg[SWI_HDL_NUMB]={0};
WORD s_wIntrSysMaskS[2]={0};
void SWIHandler(DWORD dwSWICode, DWORD* pReg0TO3, DWORD dwLr, DWORD dwspsr)
{
	if(dwSWICode>=SWI_HDL_NUMB)
	{
		EdbgOutputDebugString("Invalid swi code:%d\r\n", dwSWICode);
		return;
	}

	if(NULL!=s_pvSWIPfnS[dwSWICode])
	{
		switch(s_dwSWIVarg[dwSWICode])
		{
		case 0:
			pReg0TO3[0]=(DWORD)(*((pfnSWIHldPv0)(s_pvSWIPfnS[dwSWICode])))();
			break;
		case 1:
			pReg0TO3[0]=(DWORD)(*((pfnSWIHldPv1)(s_pvSWIPfnS[dwSWICode])))(pReg0TO3[0]);
			break;
		case 2:
			pReg0TO3[0]=(DWORD)(*((pfnSWIHldPv2)(s_pvSWIPfnS[dwSWICode])))(pReg0TO3[0], pReg0TO3[1]);
			break;
		case 3:
			pReg0TO3[0]=(DWORD)(*((pfnSWIHldPv3)(s_pvSWIPfnS[dwSWICode])))(pReg0TO3[0], pReg0TO3[1], pReg0TO3[2]);
			break;
		case 4:
			pReg0TO3[0]=(DWORD)(*((pfnSWIHldPv4)(s_pvSWIPfnS[dwSWICode])))(pReg0TO3[0], pReg0TO3[1], pReg0TO3[2], pReg0TO3[3]);
			break;
		default:
			break;
		}
	}

	EdbgOutputDebugString("SWIHandler return\r\n");
	return;
}
BOOL SVC_RegHdl(DWORD dwSvcCode, DWORD dwArgNumb, void* pfn)
{
	if( (dwSvcCode>=SWI_HDL_NUMB)
		|| (dwArgNumb>4) )
	{
		return FALSE;
	}

	s_pvSWIPfnS[dwSvcCode]=pfn;
	s_dwSWIVarg[dwSvcCode]=dwArgNumb;

	return TRUE;
}

void PrefetchAbortHandler(DWORD dwAbordAddr)
{
	EdbgOutputDebugString("\r\nPrefetchAbortHandler addr:0x%x halt!!!\r\n", dwAbordAddr);
	while(1){}
}

void DataAbortHandler(DWORD dwFAR, DWORD dwFSR, DWORD dwSPSR, DWORD dwLR)
{
	EdbgOutputDebugString("\r\nData Abort FAR:0x%x FSR:0x%x SPSR:0x%x LR:0x%x Halt!!!\r\n", dwFAR, dwFSR, dwSPSR, dwLR);
	while(1){}
}

void FIQHandler()
{
//	EdbgOutputDebugString("\r\nFIQHandler\r\n");
	InterruptHandler(1);
}

void IRQHandler()
{
//	EdbgOutputDebugString("\r\nIRQHandler\r\n");
	InterruptHandler(0);
}


// bIntrType:0<inq>, 1<firq> 
pfnIntrHdl g_pfnIntrHdlS[28]={0};		// main [0-27]
pfnIntrHdl g_pfnSysCtrlIntrHdlS[11]={0};		// sysctrl[16-26]

// bIntrType:0<inq>, 1<firq> 
void InterruptHandler(BYTE bIntrType)
{
    UINT32 status = 0;
    UINT32 statusSys = 0;
    UINT32 maskValue = 0;
    UINT32 maskValueSys = 0;

	BYTE i;
	volatile DWORD* pdwIntrMaskReg=g_pdwIntrRegs+IRQINT_MASK_REG_OFFSET/4+bIntrType;

    // Get pending interrupt(s)
    status = REG32((UINT8*)g_pdwIntrRegs + INT_STATUS_REG_OFFSET) & MASK_INT_STA_1;
    maskValue = REG32(pdwIntrMaskReg) & MASK_INT_ENA_1;
    status &= maskValue;

	if(!(status & INT_STA_SYS_CTL))
	{
		for(i=0; i<27; i++)
		{
			maskValue=(1<<i);
			if(maskValue&status)
			{
				// disable interrupt
				REG32(pdwIntrMaskReg) &= (~maskValue);
				//clear interrupt status bit
				REG32((UINT8*)g_pdwIntrRegs + INT_STATUS_REG_OFFSET) &= (~maskValue);
				if(g_pfnIntrHdlS[i])
				{
					(*g_pfnIntrHdlS[i])(i, 0, bIntrType);
				}
			}
		}
	}
	else
	{
		//clear interrupt status bit
        REG32((UINT8*)g_pdwIntrRegs + INT_STATUS_REG_OFFSET) &= ~INT_STA_SYS_CTL;

		statusSys = REG32((UINT8*)g_pdwIntrRegs + INT_STA_ENA_OFFSET) & MASK_INT_STA_2;
		maskValueSys = (REG32((UINT8 *)g_pdwIntrRegs + INT_STA_ENA_OFFSET) & MASK_INT_ENA_2) << 16;
		maskValueSys&=(s_wIntrSysMaskS[bIntrType]<<16);	// for sysintr irq fiq mask
		statusSys &= maskValueSys;

		for(i=16; i<=26; i++)
		{
			maskValueSys=(1<<i);
			if(maskValueSys&statusSys)
			{
                //clear interrupt status bit
                REG32((UINT8*)g_pdwIntrRegs + INT_STA_ENA_OFFSET) &= ~(maskValueSys>>16);
                // disable interrupt
                REG32((UINT8*)g_pdwIntrRegs + INT_STA_ENA_OFFSET) &= ~maskValueSys;
				s_wIntrSysMaskS[bIntrType] &= ~(maskValueSys>>16);

				if(g_pfnSysCtrlIntrHdlS[i-16])
				{
					(*g_pfnSysCtrlIntrHdlS[i-16])(27, i, bIntrType);
				}
			}
		}

		status = REG32((UINT8*)g_pdwIntrRegs + INT_STATUS_REG_OFFSET) & MASK_INT_STA_1;
		// must be irq, so disable fiq mask
		if(bIntrType && status)
		{
			REG32((UINT8 *)g_pdwIntrRegs + FIQINT_MASK_REG_OFFSET)&= ~INT_STA_SYS_CTL;
		}

		// fiq may disable fir sysintr for irq, enable now
		if(!bIntrType)
		{
			REG32((UINT8 *)g_pdwIntrRegs + FIQINT_MASK_REG_OFFSET)|= INT_STA_SYS_CTL;
		}

	}

}

BOOL Intr_RegHdl(BYTE bMain, BYTE bSysCtrl, pfnIntrHdl pfnHdl)
{
	if( (27<bMain)
		|| ( (16>bSysCtrl) || (26<bSysCtrl) ) )
	{
		return FALSE;
	}

	if(27==bMain)
	{
		g_pfnSysCtrlIntrHdlS[bSysCtrl-16]=pfnHdl;
	}
	else
	{
		g_pfnIntrHdlS[bMain]=pfnHdl;
	}

	return TRUE;
}

// bIntrType:0<inq>, 1<firq> 
BOOL Intr_EnHdl(BYTE bMain, BYTE bSysCtrl, BYTE bIntrType, BOOL fEn)
{
	if( (27<bMain)
		|| ( (16>bSysCtrl) || (26<bSysCtrl) ) )
	{
		return FALSE;
	}

	if(27==bMain)
	{
		if(fEn)
		{
			REG32((UINT8*)g_pdwIntrRegs + INT_STA_ENA_OFFSET) |= (1<<(bSysCtrl-16));
			s_wIntrSysMaskS[bIntrType] |= (1<<(bSysCtrl-16));
		}
		else
		{
			REG32((UINT8*)g_pdwIntrRegs + INT_STA_ENA_OFFSET) &= ~(1<<(bSysCtrl-16));
			s_wIntrSysMaskS[bIntrType] &= ~(1<<(bSysCtrl-16));
		}
	}
	else
	{
		if(fEn)
		{
			REG32((UINT8*)g_pdwIntrRegs + IRQINT_MASK_REG_OFFSET) |= (1<<bMain);
		}
		else
		{
			REG32((UINT8*)g_pdwIntrRegs + IRQINT_MASK_REG_OFFSET) &= ~(1<<bMain);
		}
	}

	return TRUE;
}


